package cc.siyecao.fastdfs.pool;

import cc.siyecao.fastdfs.extception.FastDfsException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class FdfsConnectionManager {
    @Autowired
    private FdfsConnectionFactory fdfsConnectionFactory;

    @Value("${fdfs.pool.maxIdleTime}")
    private int maxIdleTime;

    @Value("${fdfs.pool.maxCountPerEntry}")
    private int maxCountPerEntry;

    @Value("${fdfs.pool.maxWaitTime}")
    private int maxWaitTime;

    @Value("${fdfs.pool.enabled}")
    private boolean poolEnabled;


    /**
     * key is ip:port, value is ConnectionManager
     */
    private final static ConcurrentHashMap<String, FdfsConnectionPool> CP = new ConcurrentHashMap<>();

    public FdfsConnection getConnection(InetSocketAddress socketAddress) throws FastDfsException {
        if (socketAddress == null) {
            return null;
        }
        if (poolEnabled) {
            String key = getKey( socketAddress );
            FdfsConnectionPool connectionPool;
            connectionPool = CP.get( key );
            if (connectionPool == null) {
                synchronized (FdfsConnectionManager.class) {
                    connectionPool = CP.get( key );
                    if (connectionPool == null) {
                        connectionPool = new FdfsConnectionPool( fdfsConnectionFactory, maxIdleTime, maxCountPerEntry, maxWaitTime, socketAddress );
                        CP.put( key, connectionPool );
                    }
                }
            }
            return connectionPool.getConnection();
        } else {
            return fdfsConnectionFactory.create( socketAddress );
        }
    }

    public static void releaseConnection(FdfsConnection connection) throws IOException {
        if (connection == null) {
            return;
        }
        String key = getKey( connection.getInetSocketAddress() );
        FdfsConnectionPool connectionPool = CP.get( key );
        if (connectionPool != null) {
            connectionPool.releaseConnection( connection );
        } else {
            connection.close();
        }

    }

    public static void closeConnection(FdfsConnection connection) throws IOException {
        if (connection == null) {
            return;
        }
        String key = getKey( connection.getInetSocketAddress() );
        FdfsConnectionPool connectionPool = CP.get( key );
        if (connectionPool != null) {
            connectionPool.closeConnection( connection );
            connectionPool.setActiveTestFlag();
        } else {
            connection.close();
        }
    }

    private static String getKey(InetSocketAddress socketAddress) {
        if (socketAddress == null) {
            return null;
        }
        return String.format( "%s:%s", socketAddress.getAddress().getHostAddress(), socketAddress.getPort() );
    }

    @Override
    public String toString() {
        if (!CP.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            for (Map.Entry<String, FdfsConnectionPool> managerEntry : CP.entrySet()) {
                builder.append( "key:[" + managerEntry.getKey() + " ]-------- entry:" + managerEntry.getValue() + "\n" );
            }
            return builder.toString();
        }
        return null;
    }
}
